#include "ShapeContainer.h"

ShapeContainer::ShapeContainer():m_saveStamp(false)
{
	m_ShapesArray = new (vector<Shape*>);
}

bool ShapeContainer::isLegalIndex ( unsigned int index) const
{
	if ( index < 0 || index > m_ShapesArray->size())
	{
		cerr << "Error: Index out of bounds." << endl;
		return false;
	}
	return true;
}

bool ShapeContainer::getShape( unsigned int index,  Shape& shape) const
{
	if (!isLegalIndex(index))
	{
		Point p1;
		p1.set(0,0);
		shape.set(p1, 0, 0);
		return false;
	}

	shape = *m_ShapesArray->at(index);
	return true;
}

bool ShapeContainer::addRectangle()
{
	CRectangle* newRec = new CRectangle;

	if (getShapeAndAddToArray(newRec))
	{
		return true;
	}

	delete newRec;
	return false;
}

bool ShapeContainer::addCircle()
{
	Circle* newCirc = new Circle;

	if (getShapeAndAddToArray(newCirc))
	{
		return true;
	}

	delete newCirc;
	return false;
}

bool ShapeContainer::getShapeAndAddToArray(Shape* shape)
{
	if (shape->input())
	{
		m_ShapesArray->push_back (shape);
		return true;
	}

	return false;
}

bool ShapeContainer::set( unsigned int index, Shape& shape)
{
	if (!isLegalIndex (index))
		return false;

	m_ShapesArray->insert (m_ShapesArray->begin() + index, &shape);
	return true;
}

bool ShapeContainer::shapeDelete( unsigned int index)
{
	if (!isLegalIndex (index))
		return false;

	delete *(m_ShapesArray->begin() + index);
	m_ShapesArray->erase (m_ShapesArray->begin() + index);
	return true;
}

void ShapeContainer::drawAll ( unsigned int drawType)
{
	bool fill = true;

	if (this->getSize() == 0)
	{
		cout << "No Shapes to draw..." << endl;
		return;
	}
	
	if (drawType) {fill = false;}

	for (m_itr = m_ShapesArray->begin();
			m_itr != m_ShapesArray->end();
			++m_itr)
	{
		(*m_itr)->draw('*', fill);
	}
}

void ShapeContainer::drawSpecific ( unsigned int drawType,  unsigned int index , char ch) 
{
	drawAll (drawType);
	m_ShapesArray->at(index)->draw(ch ,true);
}

bool ShapeContainer::searchShape (const  Point& p1, unsigned int& index) 
{

	index = m_ShapesArray->end() - m_ShapesArray->begin() ;
	for (index; index > 0; --index)
	{
		if (((*m_ShapesArray)[index-1])->search(p1))
		{
			--index;
			return true;
		}
	}

	return false;
}

bool ShapeContainer::moveShapeToBack ( unsigned int index)
{
	if (!isLegalIndex (index))
		return false;

	Shape* temp = (*m_ShapesArray).at(index);
	(*m_ShapesArray).erase ((*m_ShapesArray).begin()+index);	
	(*m_ShapesArray).insert ((*m_ShapesArray).begin(),temp);
	
	this->setSaveStamp(false);
	return true;
}

bool ShapeContainer::moveShapeToFront ( unsigned int index)
{
	if (!isLegalIndex (index))
		return false;
	
	Shape* temp = (*m_ShapesArray)[index];	
	(*m_ShapesArray).erase ((*m_ShapesArray).begin()+index);
	(*m_ShapesArray).push_back (temp);

	this->setSaveStamp(false);
	return true;
}

bool ShapeContainer::setAxis ( unsigned int index,  int axisX, int axisY)
{
	int x, y;

	if (!isLegalIndex (index))
		return false;

	x = m_ShapesArray->at(index)->getXPoint();
	y = m_ShapesArray->at(index)->getYPoint();

	return m_ShapesArray->at(index)->setPoint(x + axisX, y + axisY);
}

bool ShapeContainer::setDirection( unsigned int index,  double dirX,  double dirY)
{
	if (!isLegalIndex (index))
		return false;

	if ((m_ShapesArray->at(index))->setDirection(dirX, dirY))
	{
		this->setSaveStamp(false);
		return true;
	}
	return false;
}

void ShapeContainer::drawToScreen (MyScreen * scr ,  unsigned int drawType,  char ch) 
{
	bool fill;

	if (this->getSize() == 0)
	{
		cout << "No Shapes to draw..." << endl;
		return;
	}

	fill = (drawType == 1 ? false : true);

	for (m_itr = m_ShapesArray->begin();
			m_itr != m_ShapesArray->end();
			++m_itr)
	{
		if ((*m_itr)->getPrintWithSplit())
			(*m_itr)->draw(ch, fill, scr, true);
		else
			(*m_itr)->draw(ch, fill, scr, false);
	}
}

void ShapeContainer::drawToScreenWithoutSplit (MyScreen * scr , unsigned int drawType, char ch) 
{
	bool fill;

	if (this->getSize() == 0)
	{
		cout << "No Shapes to draw..." << endl;
		return;
	}

	fill = (drawType == 1 ? false : true);

	for (m_itr = m_ShapesArray->begin();
			m_itr != m_ShapesArray->end();
			++m_itr)
	{
		(*m_itr)->draw(ch, fill, scr, false);
	}
}

void ShapeContainer::addTimeToAnim ()
{
	for (m_itr = m_ShapesArray->begin();
		 m_itr != m_ShapesArray->end();
		 ++m_itr)
	{
		(*m_itr)->addSumDirX();
		(*m_itr)->addSumDirY();
	}
}

void ShapeContainer::initSum()
{
	for (m_itr = m_ShapesArray->begin();
		m_itr != m_ShapesArray->end();
		++m_itr)
	{
		(*m_itr)->initSum();
	}
}

void ShapeContainer::updatePrintWithSplit ()
{
	for (m_itr = m_ShapesArray->begin();
		m_itr != m_ShapesArray->end();
		++m_itr)
	{
		if (!(*m_itr)->getPrintWithSplit())
			(*m_itr)->updatePrintWithSplit();
	}
}

void ShapeContainer::initPrintWithSplit ()
{
	for (m_itr = m_ShapesArray->begin();
		m_itr != m_ShapesArray->end();
		++m_itr)
	{
		(*m_itr)->updatePrintWithSplit();
	}
}

void ShapeContainer::drawToScreenWithCollision (MyScreen * scr) 
{
	if (this->getSize() == 0)
	{
		cout << "No Shapes to draw..." << endl;
		return;
	}

	vector<Shape*>::iterator m_itr2;

	CRectangle screenRec;
	screenRec.set (Point(-1,-1), MAX_SCREEN_X +1 , MAX_SCREEN_Y +1);

	for (m_itr = m_ShapesArray->begin();
		m_itr != m_ShapesArray->end();
		++m_itr)
	{		
		// Check collision with the screen
		(*m_itr)->handleCollision(&screenRec);
		screenRec.setDirection(0,0);

		// Check collision with every Shape
		for (m_itr2 = m_itr+1;
			m_itr2 != m_ShapesArray->end();
			++m_itr2)
		{
			// Check collision only if both of the Shapes have animation
			if ((*m_itr)->getDirX() != 0 ||
				(*m_itr)->getDirY() != 0 ||
				(*m_itr2)->getDirX() != 0 ||
				(*m_itr2)->getDirY() != 0)
			{
				(*m_itr)->handleCollision(*m_itr2);
			}
		}

		// Print Shape
		(*m_itr)->draw('*', false, scr, false);
		
		// Reset number of dir change
		(*m_itr)->resetTimesChanged ();
	}

}

void ShapeContainer::restoreOriginalDir()
{
	for (m_itr = m_ShapesArray->begin();
		m_itr != m_ShapesArray->end();
		++m_itr)
	{
		(*m_itr)->restoreOriginalDir();
	}
}

void ShapeContainer::saveOriginalDir()
{
	for (m_itr = m_ShapesArray->begin();
		m_itr != m_ShapesArray->end();
		++m_itr)
	{
		(*m_itr)->saveOriginalDir();
	}
}

void ShapeContainer::checkStuckShape() 
{
	// If there are some Shapes that located inside other Shapes - 
	// they both shouldn't move

	int index;
	MyScreen scr;
	CRectangle screenRec;
	screenRec.set (Point(-1,-1), MAX_SCREEN_X +1 , MAX_SCREEN_Y +1);
	screenRec.draw('*', false, &scr);
	for (m_itr = m_ShapesArray->begin();
		m_itr != m_ShapesArray->end();
		++m_itr)
	{

		if (!(*m_itr)->getPrintWithSplit())
		{
			(*m_itr)->setDirection (0,0);
		}


		else 
		{
				index = m_itr - m_ShapesArray->begin();
				drawAllWithoutIndex(index , &scr , '*');
				if ((*m_itr)->checkStuck(scr))
					(*m_itr)->setDirection (0,0);
				drawAllWithoutIndex(index , &scr , ' ');
		}
	}
}

void ShapeContainer::drawAllWithoutIndex(int index ,MyScreen * scr , char frame)
{
	vector<Shape *>::iterator temp_itr;

	for (temp_itr = m_ShapesArray->begin();
			temp_itr != m_ShapesArray->end();
			++temp_itr)
	{
		if ( temp_itr - m_ShapesArray->begin() != index)
				(*temp_itr)->draw(frame, false, scr);
	}
}

bool ShapeContainer::writeToText(ofstream & filename)
{
	if (m_ShapesArray->empty())
	{
		cout << "The program is empty, nothing to save" << endl;
		return false;
	}
	for (m_itr = m_ShapesArray->begin();
		m_itr != m_ShapesArray->end();
		++m_itr)
	{
		if (!(*m_itr)->writeToText(filename))
			return false;
	}
	return true;

}

ShapeContainer::~ShapeContainer()
{
	for(m_rev_itr = m_ShapesArray->rbegin();
		m_rev_itr != m_ShapesArray->rend(); ++m_rev_itr)
	{
		delete *(m_rev_itr);
	}

	m_ShapesArray->erase (m_ShapesArray->begin(), m_ShapesArray->end());
	delete m_ShapesArray;
}
	